/*!
 * \file WtRtRunner.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 *
 * \brief
 */
#include "WtRtRunner.h"
#include "ExpCtaContext.h"

#include "ExpExecuter.h"
#include "ExpParser.h"

#include "../WtCore/CtaStraContext.h"
#include "../WtCore/WtHelper.h"

#include "../WTSTools/WTSLogger.h"
#include "../WTSUtils/SignalHook.hpp"
#include "../WTSUtils/WTSCfgLoader.h"

#include "../Share/ModuleHelper.hpp"
#include "../Share/TimeUtils.hpp"

#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSVariant.hpp"

#ifdef _MSC_VER
#include "../Common/mdump.h"
#include <boost/filesystem.hpp>
//这个主要是给MiniDumper用的
const char* getModuleName() {
    static char MODULE_NAME[250] = {0};
    if (strlen(MODULE_NAME) == 0) {
        GetModuleFileName(g_dllModule, MODULE_NAME, 250);
        boost::filesystem::path p(MODULE_NAME);
        strcpy(MODULE_NAME, p.filename().string().c_str());
    }

    return MODULE_NAME;
}
#endif

WtRtRunner::WtRtRunner()
    : _data_store(NULL), _cb_cta_init(NULL), _cb_cta_tick(NULL),
      _cb_cta_calc(NULL), _cb_cta_bar(NULL), _cb_cta_cond_trigger(NULL),
      _cb_cta_sessevt(NULL), _cb_exec_cmd(NULL), _cb_exec_init(NULL),
      _cb_parser_evt(NULL), _cb_parser_sub(NULL), _cb_evt(NULL), _is_hft(false),
      _is_sel(false), _ext_fnl_bar_loader(NULL), _ext_raw_bar_loader(NULL),
      _ext_adj_fct_loader(NULL) {
#if _WIN32
#pragma message("Signal hooks disabled in WIN32")
#else
#pragma message("Signal hooks enabled in UNIX")
    install_signal_hooks([](const char* message) {
        WTSLogger::error(message);
        WTSLogger::stop();
    });
#endif
}

WtRtRunner::~WtRtRunner() {}

bool WtRtRunner::init(const char* logCfg /* = "logcfg.prop" */,
                      bool isFile /* = true */, const char* genDir) {
#ifdef _MSC_VER
    CMiniDumper::Enable(getModuleName(), true, WtHelper::getCWD().c_str());
#endif

    if (isFile) {
        std::string path = WtHelper::getCWD() + logCfg;
        WTSLogger::init(path.c_str(), true, this);
    }
    else {
        WTSLogger::init(logCfg, false, this);
    }

    WtHelper::setInstDir(getBinDir());
    WtHelper::setGenerateDir(StrUtil::standardisePath(genDir).c_str());
    return true;
}

void WtRtRunner::registerEvtCallback(FuncEventCallback cbEvt) {
    _cb_evt = cbEvt;

    _cta_engine.regEventListener(this);
}

void WtRtRunner::registerParserPorter(FuncParserEvtCallback cbEvt,
                                      FuncParserSubCallback cbSub) {
    _cb_parser_evt = cbEvt;
    _cb_parser_sub = cbSub;

    WTSLogger::info("Callbacks of Extented Parser registration done");
}

void WtRtRunner::registerExecuterPorter(FuncExecInitCallback cbInit,
                                        FuncExecCmdCallback cbExec) {
    _cb_exec_init = cbInit;
    _cb_exec_cmd = cbExec;

    WTSLogger::info("Callbacks of Extented Executer registration done");
}

void WtRtRunner::registerCtaCallbacks(
    FuncStraInitCallback cbInit, FuncStraTickCallback cbTick,
    FuncStraCalcCallback cbCalc, FuncStraBarCallback cbBar,
    FuncSessionEvtCallback cbSessEvt,
    FuncStraCondTriggerCallback cbCondTrigger /* = NULL */) {
    _cb_cta_init = cbInit;
    _cb_cta_tick = cbTick;
    _cb_cta_calc = cbCalc;
    _cb_cta_bar = cbBar;
    _cb_cta_sessevt = cbSessEvt;
    _cb_cta_cond_trigger = cbCondTrigger;

    WTSLogger::info("Callbacks of CTA engine registration done");
}

bool WtRtRunner::loadFinalHisBars(void* obj, const char* stdCode,
                                  WTSKlinePeriod period, FuncReadBars cb) {
    StdUniqueLock lock(_feed_mtx);
    if (_ext_fnl_bar_loader == NULL)
        return false;

    _feed_obj = obj;
    _feeder_bars = cb;

    switch (period) {
    case KP_DAY:
        return _ext_fnl_bar_loader(stdCode, "d1");
    case KP_Minute1:
        return _ext_fnl_bar_loader(stdCode, "m1");
    case KP_Minute5:
        return _ext_fnl_bar_loader(stdCode, "m5");
    default: {
        WTSLogger::error("Unsupported period of extended data loader");
        return false;
    }
    }
}

bool WtRtRunner::loadRawHisBars(void* obj, const char* stdCode,
                                WTSKlinePeriod period, FuncReadBars cb) {
    StdUniqueLock lock(_feed_mtx);
    if (_ext_raw_bar_loader == NULL)
        return false;

    _feed_obj = obj;
    _feeder_bars = cb;

    switch (period) {
    case KP_DAY:
        return _ext_raw_bar_loader(stdCode, "d1");
    case KP_Minute1:
        return _ext_raw_bar_loader(stdCode, "m1");
    case KP_Minute5:
        return _ext_raw_bar_loader(stdCode, "m5");
    default: {
        WTSLogger::error("Unsupported period of extended data loader");
        return false;
    }
    }
}

bool WtRtRunner::loadAllAdjFactors(void* obj, FuncReadFactors cb) {
    StdUniqueLock lock(_feed_mtx);
    if (_ext_adj_fct_loader == NULL)
        return false;

    _feed_obj = obj;
    _feeder_fcts = cb;

    return _ext_adj_fct_loader("");
}

bool WtRtRunner::loadAdjFactors(void* obj, const char* stdCode,
                                FuncReadFactors cb) {
    StdUniqueLock lock(_feed_mtx);
    if (_ext_adj_fct_loader == NULL)
        return false;

    _feed_obj = obj;
    _feeder_fcts = cb;

    return _ext_adj_fct_loader(stdCode);
}

void WtRtRunner::feedAdjFactors(const char* stdCode, uint32_t* dates,
                                double* factors, uint32_t count) {
    _feeder_fcts(_feed_obj, stdCode, dates, factors, count);
}

void WtRtRunner::feedRawBars(WTSBarStruct* bars, uint32_t count) {
    if (_ext_fnl_bar_loader == NULL) {
        WTSLogger::error(
            "Cannot feed bars because of no extented bar loader registered.");
        return;
    }

    _feeder_bars(_feed_obj, bars, count);
}

bool WtRtRunner::createExtParser(const char* id) {
    ParserAdapterPtr adapter(new ParserAdapter);
    ExpParser* parser = new ExpParser(id);
    adapter->initExt(id, parser, _engine, _engine->get_basedata_mgr(),
                     _engine->get_hot_mgr());
    _parsers.addAdapter(id, adapter);
    WTSLogger::info("Extended parser created");
    return true;
}

bool WtRtRunner::createExtExecuter(const char* id) {
    ExpExecuter* executer = new ExpExecuter(id);
    executer->init();
    _cta_engine.addExecuter(ExecCmdPtr(executer));
    WTSLogger::info("Extended Executer created");
    return true;
}

uint32_t WtRtRunner::createCtaContext(const char* name,
                                      int32_t slippage /* = 0 */) {
    ExpCtaContext* ctx = new ExpCtaContext(&_cta_engine, name, slippage);
    _cta_engine.addContext(CtaContextPtr(ctx));
    return ctx->id();
}

const char* WtRtRunner::get_raw_stdcode(const char* stdCode) {
    static thread_local std::string s;
    s = _engine->get_rawcode(stdCode);
    return s.c_str();
}

CtaContextPtr WtRtRunner::getCtaContext(uint32_t id) {
    return _cta_engine.getContext(id);
}

void WtRtRunner::ctx_on_bar(uint32_t id, const char* stdCode,
                            const char* period, WTSBarStruct* newBar,
                            EngineType eType /* = ET_CTA */) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_bar)
            _cb_cta_bar(id, stdCode, period, newBar);
        break;
    case ET_HFT:
        break;
    case ET_SEL:
        break;
    default:
        break;
    }
}

void WtRtRunner::ctx_on_calc(uint32_t id, uint32_t curDate, uint32_t curTime,
                             EngineType eType /* = ET_CTA */) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_calc)
            _cb_cta_calc(id, curDate, curTime);
        break;
    case ET_SEL:
        break;
    default:
        break;
    }
}

void WtRtRunner::ctx_on_cond_triggered(uint32_t id, const char* stdCode,
                                       double target, double price,
                                       const char* usertag,
                                       EngineType eType /* = ET_CTA */) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_cond_trigger)
            _cb_cta_cond_trigger(id, stdCode, target, price, usertag);
        break;
    default:
        break;
    }
}

void WtRtRunner::ctx_on_init(uint32_t id, EngineType eType /* = ET_CTA*/) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_init)
            _cb_cta_init(id);
        break;
    case ET_HFT:
        break;
    case ET_SEL:
        break;
    default:
        break;
    }
}

void WtRtRunner::ctx_on_session_event(uint32_t id, uint32_t curTDate,
                                      bool isBegin /* = true */,
                                      EngineType eType /* = ET_CTA */) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_sessevt)
            _cb_cta_sessevt(id, curTDate, isBegin);
        break;
    case ET_HFT:
        break;
    case ET_SEL:
        break;
    default:
        break;
    }
}

void WtRtRunner::ctx_on_tick(uint32_t id, const char* stdCode,
                             WTSTickData* newTick,
                             EngineType eType /* = ET_CTA */) {
    switch (eType) {
    case ET_CTA:
        if (_cb_cta_tick)
            _cb_cta_tick(id, stdCode, &newTick->getTickStruct());
        break;
    case ET_HFT:
        break;
    case ET_SEL:
        break;
    default:
        break;
    }
}

bool WtRtRunner::config(const char* cfgFile, bool isFile /* = true */) {
    _config = isFile ? WTSCfgLoader::load_from_file(cfgFile)
                     : WTSCfgLoader::load_from_content(cfgFile, false);

    //基础数据文件
    WTSVariant* cfgBF = _config->get("basefiles");
    if (cfgBF->get("session")) {
        _bd_mgr.loadSessions(cfgBF->getCString("session"));
        WTSLogger::info("Trading sessions loaded");
    }

    WTSVariant* cfgItem = cfgBF->get("commodity");
    if (cfgItem) {
        if (cfgItem->type() == WTSVariant::VT_String) {
            _bd_mgr.loadCommodities(cfgItem->asCString());
        }
        else if (cfgItem->type() == WTSVariant::VT_Array) {
            for (uint32_t i = 0; i < cfgItem->size(); i++) {
                _bd_mgr.loadCommodities(cfgItem->get(i)->asCString());
            }
        }
    }

    cfgItem = cfgBF->get("contract");
    if (cfgItem) {
        if (cfgItem->type() == WTSVariant::VT_String) {
            _bd_mgr.loadContracts(cfgItem->asCString());
        }
        else if (cfgItem->type() == WTSVariant::VT_Array) {
            for (uint32_t i = 0; i < cfgItem->size(); i++) {
                _bd_mgr.loadContracts(cfgItem->get(i)->asCString());
            }
        }
    }

    if (cfgBF->get("holiday")) {
        _bd_mgr.loadHolidays(cfgBF->getCString("holiday"));
        WTSLogger::log_raw(LL_INFO, "Holidays loaded");
    }

    if (cfgBF->get("hot")) {
        _hot_mgr.loadHots(cfgBF->getCString("hot"));
        WTSLogger::log_raw(LL_INFO, "Hot rules loaded");
    }

    if (cfgBF->get("second")) {
        _hot_mgr.loadSeconds(cfgBF->getCString("second"));
        WTSLogger::log_raw(LL_INFO, "Second rules loaded");
    }

    if (cfgBF->has("rules")) {
        auto cfgRules = cfgBF->get("rules");
        auto tags = cfgRules->memberNames();
        for (const std::string& ruleTag : tags) {
            _hot_mgr.loadCustomRules(ruleTag.c_str(),
                                     cfgRules->getCString(ruleTag.c_str()));
            WTSLogger::info("{} rules loaded from {}", ruleTag,
                            cfgRules->getCString(ruleTag.c_str()));
        }
    }

    //初始化运行环境
    initEngine();

    //初始化数据管理
    initDataMgr();

    //初始化开平策略
    if (!initActionPolicy())
        return false;

    //初始化行情通道
    WTSVariant* cfgParser = _config->get("parsers");
    if (cfgParser) {
        if (cfgParser->type() == WTSVariant::VT_String) {
            const char* filename = cfgParser->asCString();
            if (StdFile::exists(filename)) {
                WTSLogger::info("Reading parser config from {}...", filename);
                WTSVariant* var = WTSCfgLoader::load_from_file(filename);
                if (var) {
                    if (!initParsers(var->get("parsers")))
                        WTSLogger::error("Loading parsers failed");
                    var->release();
                }
                else {
                    WTSLogger::error("Loading parser config {} failed",
                                     filename);
                }
            }
            else {
                WTSLogger::error("Parser configuration {} not exists",
                                 filename);
            }
        }
        else if (cfgParser->type() == WTSVariant::VT_Array) {
            initParsers(cfgParser);
        }
    }

    //初始化交易通道
    WTSVariant* cfgTraders = _config->get("traders");
    if (cfgTraders) {
        if (cfgTraders->type() == WTSVariant::VT_String) {
            const char* filename = cfgTraders->asCString();
            if (StdFile::exists(filename)) {
                WTSLogger::info("Reading trader config from {}...", filename);
                WTSVariant* var = WTSCfgLoader::load_from_file(filename);
                if (var) {
                    if (!initTraders(var->get("traders")))
                        WTSLogger::error("Loading traders failed");
                    var->release();
                }
                else {
                    WTSLogger::error("Loading trader config {} failed",
                                     filename);
                }
            }
            else {
                WTSLogger::error("Trader configuration {} not exists",
                                 filename);
            }
        }
        else if (cfgTraders->type() == WTSVariant::VT_Array) {
            initTraders(cfgTraders);
        }
    }

    //初始化事件推送器
    initEvtNotifier();

    //如果不是高频引擎,则需要配置执行模块
    if (!_is_hft) {
        WTSVariant* cfgExec = _config->get("executers");
        if (cfgExec != NULL) {
            if (cfgExec->type() == WTSVariant::VT_String) {
                const char* filename = cfgExec->asCString();
                if (StdFile::exists(filename)) {
                    WTSLogger::info("Reading executer config from {}...",
                                    filename);
                    WTSVariant* var = WTSCfgLoader::load_from_file(filename);
                    if (var) {
                        if (!initExecuters(var->get("executers")))
                            WTSLogger::error("Loading executers failed");

                        WTSVariant* c = var->get("routers");
                        if (c != NULL)
                            _cta_engine.loadRouterRules(c);

                        var->release();
                    }
                    else {
                        WTSLogger::error("Loading executer config {} failed",
                                         filename);
                    }
                }
                else {
                    WTSLogger::error("Trader configuration {} not exists",
                                     filename);
                }
            }
            else if (cfgExec->type() == WTSVariant::VT_Array) {
                initExecuters(cfgExec);
            }
        }

        WTSVariant* cfgRouter = _config->get("routers");
        if (cfgRouter != NULL)
            _cta_engine.loadRouterRules(cfgRouter);
    }

    if (!_is_hft)
        initCtaStrategies();

    return true;
}

bool WtRtRunner::initCtaStrategies() {
    WTSVariant* cfg = _config->get("strategies");
    if (cfg == NULL || cfg->type() != WTSVariant::VT_Object)
        return false;

    cfg = cfg->get("cta");
    if (cfg == NULL || cfg->type() != WTSVariant::VT_Array)
        return false;

    for (uint32_t idx = 0; idx < cfg->size(); idx++) {
        WTSVariant* cfgItem = cfg->get(idx);
        if (!cfgItem->getBoolean("active"))
            continue;

        const char* id = cfgItem->getCString("id");
        const char* name = cfgItem->getCString("name");
        int32_t slippage = cfgItem->getInt32("slippage");
        CtaStrategyPtr stra = _cta_mgr.createStrategy(name, id);
        stra->self()->init(cfgItem->get("params"));
        CtaStraContext* ctx = new CtaStraContext(&_cta_engine, id, slippage);
        ctx->set_strategy(stra->self());
        _cta_engine.addContext(CtaContextPtr(ctx));
    }

    return true;
}

bool WtRtRunner::initEngine() {
    WTSVariant* cfg = _config->get("env");
    if (cfg == NULL)
        return false;

    const char* name = cfg->getCString("name");

    if (strlen(name) == 0 || wt_stricmp(name, "cta") == 0) {
        _is_hft = false;
        _is_sel = false;
    }
    else if (wt_stricmp(name, "sel") == 0) {
        _is_sel = true;
    }
    else // if (wt_stricmp(name, "hft") == 0)
    {
        _is_hft = true;
    }

    if (_is_hft) {
    }
    else if (_is_sel) {
    }
    else {
        WTSLogger::info("Trading environment initialized, engine name: CTA");
        _cta_engine.init(cfg, &_bd_mgr, &_data_mgr, &_hot_mgr, &_notifier);
        _engine = &_cta_engine;
    }

    _engine->set_adapter_mgr(&_traders);

    return true;
}

bool WtRtRunner::initDataMgr() {
    WTSVariant* cfg = _config->get("data");
    if (cfg == NULL)
        return false;

    _data_mgr.regsiter_loader(this);

    _data_mgr.init(cfg, _engine);

    WTSLogger::log_raw(LL_INFO, "Data manager initialized");
    return true;
}

bool WtRtRunner::initParsers(WTSVariant* cfgParsers) {
    if (cfgParsers == NULL || cfgParsers->type() != WTSVariant::VT_Array)
        return false;

    uint32_t count = 0;
    for (uint32_t idx = 0; idx < cfgParsers->size(); idx++) {
        WTSVariant* cfgItem = cfgParsers->get(idx);
        if (!cfgItem->getBoolean("active"))
            continue;

        const char* id = cfgItem->getCString("id");

        // By Wesley @ 2021.12.14
        // 如果id为空，则生成自动id
        std::string realid = id;
        if (realid.empty()) {
            static uint32_t auto_parserid = 1000;
            realid = fmt::format("auto_parser_{}", auto_parserid++);
        }

        ParserAdapterPtr adapter(new ParserAdapter);
        adapter->init(realid.c_str(), cfgItem, _engine,
                      _engine->get_basedata_mgr(), _engine->get_hot_mgr());
        _parsers.addAdapter(realid.c_str(), adapter);

        count++;
    }

    WTSLogger::info("{} parsers loaded", count);

    return true;
}

bool WtRtRunner::initExecuters(WTSVariant* cfgExecuter) {
    if (cfgExecuter == NULL || cfgExecuter->type() != WTSVariant::VT_Array)
        return false;

    //先加载自带的执行器工厂
    std::string path = WtHelper::getInstDir() + "executer//";
    _exe_factory.loadFactories(path.c_str());

    uint32_t count = 0;
    for (uint32_t idx = 0; idx < cfgExecuter->size(); idx++) {
        WTSVariant* cfgItem = cfgExecuter->get(idx);
        if (!cfgItem->getBoolean("active"))
            continue;

        const char* id = cfgItem->getCString("id");
        std::string name = cfgItem->getCString("name"); // local,diff,dist
        if (name.empty())
            name = "local";

        if (name == "local") {
            WtLocalExecuter* executer =
                new WtLocalExecuter(&_exe_factory, id, &_data_mgr);
            if (!executer->init(cfgItem))
                return false;

            const char* tid = cfgItem->getCString("trader");
            if (strlen(tid) == 0) {
                WTSLogger::error("No Trader configured for Executer {}", id);
            }
            else {
                TraderAdapterPtr trader = _traders.getAdapter(tid);
                if (trader) {
                    executer->setTrader(trader.get());
                    trader->addSink(executer);
                }
                else {
                    WTSLogger::error("Trader {} not exists, cannot configured "
                                     "for executer %s",
                                     tid, id);
                }
            }

            _cta_engine.addExecuter(ExecCmdPtr(executer));
        }
        else if (name == "diff") {
            WtDiffExecuter* executer =
                new WtDiffExecuter(&_exe_factory, id, &_data_mgr, &_bd_mgr);
            if (!executer->init(cfgItem))
                return false;

            const char* tid = cfgItem->getCString("trader");
            if (strlen(tid) == 0) {
                WTSLogger::error("No Trader configured for Executer {}", id);
            }
            else {
                TraderAdapterPtr trader = _traders.getAdapter(tid);
                if (trader) {
                    executer->setTrader(trader.get());
                    trader->addSink(executer);
                }
                else {
                    WTSLogger::error("Trader {} not exists, cannot configured "
                                     "for executer %s",
                                     tid, id);
                }
            }

            _cta_engine.addExecuter(ExecCmdPtr(executer));
        }
        else if (name == "arbi") {
            WtArbiExecuter* executer =
                new WtArbiExecuter(&_exe_factory, id, &_data_mgr);
            if (!executer->init(cfgItem))
                return false;

            const char* tid = cfgItem->getCString("trader");
            if (strlen(tid) == 0) {
                WTSLogger::error("No Trader configured for Executer {}", id);
            }
            else {
                TraderAdapterPtr trader = _traders.getAdapter(tid);
                if (trader) {
                    executer->setTrader(trader.get());
                    trader->addSink(executer);
                }
                else {
                    WTSLogger::error("Trader {} not exists, cannot configured "
                                     "for executer %s",
                                     tid, id);
                }
            }

            _cta_engine.addExecuter(ExecCmdPtr(executer));
        }
        else {
            WtDistExecuter* executer = new WtDistExecuter(id);
            if (!executer->init(cfgItem))
                return false;

            _cta_engine.addExecuter(ExecCmdPtr(executer));
        }

        count++;
    }

    WTSLogger::info("{} executers loaded", count);

    return true;
}

bool WtRtRunner::initEvtNotifier() {
    WTSVariant* cfg = _config->get("notifier");
    if (cfg == NULL || cfg->type() != WTSVariant::VT_Object)
        return false;

    _notifier.init(cfg);

    return true;
}

bool WtRtRunner::initTraders(WTSVariant* cfgTraders) {
    if (cfgTraders == NULL || cfgTraders->type() != WTSVariant::VT_Array)
        return false;

    uint32_t count = 0;
    for (uint32_t idx = 0; idx < cfgTraders->size(); idx++) {
        WTSVariant* cfgItem = cfgTraders->get(idx);
        if (!cfgItem->getBoolean("active"))
            continue;

        const char* id = cfgItem->getCString("id");

        TraderAdapterPtr adapter(new TraderAdapter(&_notifier));
        adapter->init(id, cfgItem, &_bd_mgr, &_act_policy);

        _traders.addAdapter(id, adapter);
        count++;
    }

    WTSLogger::info("{} traders loaded", count);

    return true;
}

void WtRtRunner::run(bool bAsync /* = false */) {
    try {
        _parsers.run();
        _traders.run();

        _engine->run(bAsync);
    } catch (...) {
        print_stack_trace(
            [](const char* message) { WTSLogger::error(message); });
    }
}

const char* LOG_TAGS[] = {
    "all", "debug", "info", "warn", "error", "fatal", "none",
};

void WtRtRunner::handleLogAppend(WTSLogLevel ll, const char* msg) {
    _notifier.notify_log(LOG_TAGS[ll - 100], msg);
}

void WtRtRunner::release() { WTSLogger::stop(); }

bool WtRtRunner::initActionPolicy() {
    const char* action_file = _config->getCString("bspolicy");
    if (strlen(action_file) <= 0)
        return false;

    bool ret = _act_policy.init(action_file);
    WTSLogger::info("Action policies initialized");
    return ret;
}

bool WtRtRunner::addCtaFactories(const char* folder) {
    return _cta_mgr.loadFactories(folder);
}

bool WtRtRunner::addExeFactories(const char* folder) {
    return _exe_factory.loadFactories(folder);
}

#pragma region "Extended Parser"
void WtRtRunner::parser_init(const char* id) {
    if (_cb_parser_evt)
        _cb_parser_evt(EVENT_PARSER_INIT, id);
}

void WtRtRunner::parser_connect(const char* id) {
    if (_cb_parser_evt)
        _cb_parser_evt(EVENT_PARSER_CONNECT, id);
}

void WtRtRunner::parser_disconnect(const char* id) {
    if (_cb_parser_evt)
        _cb_parser_evt(EVENT_PARSER_DISCONNECT, id);
}

void WtRtRunner::parser_release(const char* id) {
    if (_cb_parser_evt)
        _cb_parser_evt(EVENT_PARSER_RELEASE, id);
}

void WtRtRunner::parser_subscribe(const char* id, const char* code) {
    if (_cb_parser_sub)
        _cb_parser_sub(id, code, true);
}

void WtRtRunner::parser_unsubscribe(const char* id, const char* code) {
    if (_cb_parser_sub)
        _cb_parser_sub(id, code, false);
}

void WtRtRunner::on_ext_parser_quote(const char* id, WTSTickStruct* curTick,
                                     uint32_t uProcFlag) {
    ParserAdapterPtr adapter = _parsers.getAdapter(id);
    if (adapter) {
        WTSTickData* newTick = WTSTickData::create(*curTick);
        adapter->handleQuote(newTick, uProcFlag);
        newTick->release();
    }
    else {
        WTSLogger::warn("Parser {} not exists", id);
    }
}

#pragma endregion

#pragma region "Extended Executer"
void WtRtRunner::executer_init(const char* id) {
    if (_cb_exec_init)
        _cb_exec_init(id);
}

void WtRtRunner::executer_set_position(const char* id, const char* stdCode,
                                       double target) {
    if (_cb_exec_cmd)
        _cb_exec_cmd(id, stdCode, target);
}
#pragma endregion